package com.apexsoft.monitor.front.console.magent.om;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apexsoft.front.common.config.CommonConfig;
import com.apexsoft.front.common.support.Result;
import com.apexsoft.front.common.utils.Md5Util;
import com.apexsoft.front.common.utils.SpringContextUtil;
import com.apexsoft.monitor.common.MonitorConstant;
import com.apexsoft.monitor.common.http.HttpHelper;
import com.apexsoft.monitor.front.console.app.om.AppNode;
import com.apexsoft.monitor.front.console.app.service.AppNodeService;
import com.apexsoft.monitor.front.console.host.om.Host;
import com.apexsoft.monitor.front.console.scheme.service.LinkService;
import com.apexsoft.monitor.front.console.task.service.TaskService;
import com.apexsoft.monitor.ssh.util.ShellUtils;
import org.apache.commons.collections.map.HashedMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Map;
import java.util.Set;

/**
 * 监控进程
 */
public class MonitorMagent {

    private static final Logger log = LogManager.getRootLogger();
    private Host host;     //主机对象

    public MonitorMagent(Host host){
        this.host = host;
    }
    public Host getHost(){
        return this.host;
    }

    /**
     * 测试主机连接
     * @return
     */
    public JSONObject checkConnect(){
        ShellUtils shellUtils = new ShellUtils(this.host);
        JSONObject result = shellUtils.connect("test");
        shellUtils.closeSession();
        return result;
    }

    /**
     * 部署监控服务
     * @return
     */
    public JSONObject startMagent(){
        JSONObject result = new JSONObject();
        ShellUtils shellUtils = new ShellUtils(this.host);
        try {
            shellUtils.connect("");
            result = shellUtils.execCmd("ps -ef | grep "+MonitorConstant.MAGENT_NAME);
            if(result.getInteger("code") == -1){
                return result;
            }
            //服务是否已存
            boolean isService = false;
            String[] array = result.getString("note").split("\\n");
            for(String val :array){
                if(val.indexOf(this.host.getHostDir())!=-1
                        && val.indexOf(String.valueOf(this.host.getAgentPort()))!=-1){
                    isService = true;
                    break;
                }
            }
            //存在,什么都不做,不存在启动服务
            if(!isService){
                shellUtils.putFile(this.host.getHostDir());
                shellUtils.execCmd("chmod a+x "+this.host.getHostDir()+"/"+MonitorConstant.MAGENT_NAME);
                //mAgent 9009 amqp://admin:apexsoft123@192.168.3.134:5672/
                //拼接队列地址
                String mqHostIp = CommonConfig.getString("MQ.HOST");
                String mqPort = CommonConfig.getString("MQ.PORT");
                String mqUserName = CommonConfig.getString("MQ.USERNAME");
                String mqPassword = CommonConfig.getString("MQ.PASSWORD");
                String mqUrl = " amqp://"+mqUserName+":"+mqPassword+"@"+mqHostIp+":"+mqPort+"/";
                result = shellUtils.execCmd("nohup "+host.getHostDir()+"/"+MonitorConstant.MAGENT_NAME+" "+host.getAgentPort()+mqUrl+" > /dev/null &");
            }
            return result;
        }catch (Exception e){
            log.error(e);
            result.put(Result.CODE, Result.EC_1000);
            result.put(Result.NOTE, e.getMessage());
        }finally {
            shellUtils.closeSession();
        }
        return result;
    }

    /**
     * 关闭监控服务
     */
    public JSONObject shutdowMagent(){
        JSONObject result = new JSONObject();
        ShellUtils shellUtils = new ShellUtils(this.host);
        try {
            shellUtils.connect("");
            if(magentIsExist(shellUtils)){
                result = shellUtils.execCmd("killall "+MonitorConstant.MAGENT_NAME);
            }
        }catch (Exception e){
            log.error(e);
            result.put(Result.CODE,Result.EC_1000);
            result.put(Result.NOTE,e.getMessage());
        }finally {
            shellUtils.closeSession();
        }
        return result;
    }


    /**
     * 检测心跳
     * @return
     */
    public JSONObject checkHeartbeat(){
        JSONObject result = new JSONObject();
        try {
            JSONObject obj = new JSONObject();
            obj.put("func", "Heartbeat");
            AppNodeService appNodeSvc = (AppNodeService) SpringContextUtil.getBean("appNodeService");
            TaskService taskSvc = (TaskService) SpringContextUtil.getBean("taskService");
            LinkService linkSvc = (LinkService) SpringContextUtil.getBean("linkService");
            JSONObject nodeRes = appNodeSvc.queryNodesByHostCode(this.host.getHostCode());
            if (nodeRes.getIntValue(Result.CODE) > 0 && nodeRes.getIntValue(Result.COUNT) > 0) {
                JSONArray nodes = nodeRes.getJSONArray(Result.RECORDS);
                JSONArray newNodes =  new JSONArray();
                for (int i = 0; i < nodes.size(); i++) {
                    JSONObject node = nodes.getJSONObject(i);
                    JSONArray tasks = new JSONArray();
                    //查询任务
                    JSONObject taskRest = taskSvc.queryTaskByNodeCode(node.getString("nodeCode"));
                    if(taskRest.getIntValue(Result.CODE)>0){
                        tasks.addAll(formatTasks(taskRest.getJSONArray(Result.ROWS),node));
                    }

                    //根据节点查询链路
                    JSONObject linkRest = linkSvc.selectByStartNode(node.getString("nodeCode"));
                    if(linkRest.getIntValue(Result.CODE)>0){
                        tasks.addAll(formatLinks(linkRest.getJSONArray(Result.ROWS),node));
                    }
                    node.put("tasks", tasks);
                    newNodes.add(formatNode(node));
                }
                obj.put("nodes", newNodes);
            } else {
                obj.put("nodes", new JSONArray());
            }
            log.info("心跳包："+obj.toJSONString());
            String url = "http://"+this.host.getHostIp()+":"+this.host.getAgentPort()+"/ctrl";//"http://192.168.3.28:9001/ctrl";
            Map<String,String> headerMap = new HashedMap();
            headerMap.put(MonitorConstant.MAGENT_HEARDER_KEY,MonitorConstant.MAGENT_HEARDER_VALUE);
            String retStr = (String)HttpHelper.post(url,obj.toJSONString(),headerMap);
            log.info("心跳返回结果："+retStr);
            result = JSON.parseObject(retStr);
        }catch(Exception e){
            log.error(e);
            result.put(Result.CODE,Result.EC_1000);
            result.put(Result.NOTE,e.getMessage());
        }
        return result;
    }

    /**
     * 获取主机信息
     */
    public JSONObject getMagentInfo(){
        JSONObject result = new JSONObject();
        result.put("magentStatus","0");            //0|异常  1|正常
        result.put("errorMessage","");      //异常信息
        result.put("linkStatusList",new JSONArray());
        result.put("nodeStatusList",new JSONArray());
        boolean heartIsExist = false;
        ShellUtils shellUtils = null;
        try{
            //轮询发送心跳
            JSONObject heartRest = null;
            for(int i=0;i<MonitorConstant.TRY_TIMES;i++){
               heartRest = checkHeartbeat();
                if(heartRest.getIntValue("code")>0){
                    result.put("magentStatus","1");
                    result.put("magentVersion",heartRest.getDoubleValue("version"));
                    result.putAll(heartRest.getJSONObject("hostinfo"));
                    result.put("linkStatusList",heartRest.getJSONArray("link_status_list"));
                    result.put("nodeStatusList",heartRest.getJSONArray("node_status_list"));
                    heartIsExist = true;
                    break;
                }
                Thread.sleep(1000);
            }
            //轮询发送心跳过后心跳依然不存在
            if(!heartIsExist){
                shellUtils = new ShellUtils(this.host);
                JSONObject connectRest = shellUtils.connect("");
                if(connectRest.getIntValue("code")<0){
                    result.put("errorMessage",connectRest.getString("note"));
                    return result;
                }
                //判断监控成是否存在
                boolean magentIsExist = magentIsExist(shellUtils);
                if(magentIsExist){
                    //监控代理程序存在，心跳发送失败
                    result.put("errorMessage",heartRest.getString("note"));
                }else{
                    //监控代理程序不存在，拷贝文件--》启动监控代理程序
                    shellUtils.putFile(this.host.getHostDir());
                    shellUtils.execCmd("chmod a+x "+this.host.getHostDir()+"/"+MonitorConstant.MAGENT_NAME);
                    //拼接队列地址 mAgent 9009 amqp://admin:apexsoft123@192.168.3.134:5672/
                    String mqHostIp = CommonConfig.getString("MQ.HOST");
                    String mqPort = CommonConfig.getString("MQ.PORT");
                    String mqUserName = CommonConfig.getString("MQ.USERNAME");
                    String mqPassword = CommonConfig.getString("MQ.PASSWORD");
                    String mqUrl = " amqp://"+mqUserName+":"+mqPassword+"@"+mqHostIp+":"+mqPort+"/";
                    shellUtils.execCmd("nohup "+host.getHostDir()+"/"+MonitorConstant.MAGENT_NAME+" "+host.getAgentPort()+mqUrl+" > /dev/null &");
                    //判断监控成是否存在
                    boolean magentIsExistSecond = magentIsExist(shellUtils);
                    if(magentIsExistSecond){
                        //再次轮询发送心跳
                        boolean heatbeatSecond = false;
                        JSONObject heartRestSecond = null;
                        for(int i=0;i<MonitorConstant.TRY_TIMES;i++){
                            heartRestSecond = checkHeartbeat();
                            if(heartRestSecond.getIntValue("code")>0){
                                heatbeatSecond = true;
                                result.put("magentStatus","1");
                                result.put("magentVersion",heartRestSecond.getJSONObject("version"));
                                result.putAll(heartRestSecond.getJSONObject("hostinfo"));
                                result.put("linkStatusList",heartRestSecond.getJSONObject("link_status_list"));
                                result.put("nodeStatusList",heartRestSecond.getJSONObject("node_status_list"));
                                break;
                            }
                            Thread.sleep(1000);
                        }
                        if(!heatbeatSecond){
                            result.put("errorMessage",heartRestSecond.getString("note"));
                        }
                    }else{
                        //监控代理程序启动失败
                        result.put("errorMessage","监控代理程序启动失败");
                    }
                }
            }
        }catch (Exception e){
            result.put("errorMessage",e.getMessage());
        }finally {
            if(shellUtils!=null){
                shellUtils.closeSession();
            }
        }
        return result;
    }

    /**
     * ssh 判断监控程序是否存在
     *
     */
    public boolean magentIsExist(ShellUtils shellUtils){
        boolean magentIsExist = false;
        try{
            JSONObject result = shellUtils.execCmd("ps -ef|grep "+MonitorConstant.MAGENT_NAME);
            if(result.getIntValue("code")>0) {
                String[] array = result.getString("note").split("\\n");
                if (array.length > 2) {
                    magentIsExist = true;
                }
            }
        }catch(Exception e) {
            log.error(e);
        }
        return magentIsExist;
    }


    /**
     * 中间件任务格式化
     * @param tasks
     * @param appNode
     * @return
     */
    private JSONArray formatTasks(JSONArray tasks, JSONObject appNode) {
        JSONArray newTasks = new JSONArray();
        for(int i=0;i<tasks.size();i++){
            JSONObject task = tasks.getJSONObject(i);
            JSONObject newTask = new JSONObject();
            newTask.put("task_code",task.getString("taskCode"));
            newTask.put("task_name",task.getString("taskName"));
            newTask.put("task_type",task.getString("type"));
            newTask.put("value",task.getString("value").replace("$",appNode.getString("basePath")));
            String attribute = task.getString("attribute");
            String attr = "";
            if(attribute!=null && !"".equals(attribute)){
                try{
                    JSONObject attrObj = JSON.parseObject(attribute);
                    Set<String> keys = attrObj.keySet();
                    if(keys.size()>0){
                        for(String key:keys){
                            attr += attrObj.getString(key)+";";
                        }
                        if(attr.length()>0){
                            attr = attr.substring(0,attr.length()-1);
                        }
                    }
                }catch(Exception e){
                    log.error(e);
                    attr = "";
                }
            }
            newTask.put("attr",attr);
            newTask.put("target","");
            newTasks.add(newTask);
        }
        return newTasks;
    }

    /**
     * 中间件链路格式化
     * @param tasks
     * @param appNode
     * @return
     */
    private JSONArray formatLinks(JSONArray tasks, JSONObject appNode) {
        AppNodeService appNodeSvc = (AppNodeService) SpringContextUtil.getBean("appNodeService");
        JSONArray newTasks = new JSONArray();
        for(int i=0;i<tasks.size();i++){
            JSONObject task = tasks.getJSONObject(i);
            AppNode nodeTemp = appNodeSvc.getByCode(task.getString("endNode"));
            JSONObject newTask = new JSONObject();
            newTask.put("task_name",nodeTemp.getNodeType()+"链路");
            newTask.put("task_type","link");
            newTask.put("value",nodeTemp.getNodeLink());
            newTask.put("attr",nodeTemp.getNodeType());
            newTask.put("target",nodeTemp.getNodeCode());
            newTask.put("task_code", Md5Util.encryption(newTask.toJSONString()));
            newTasks.add(newTask);
        }
        return newTasks;
    }

    /**
     * 中间件格式化
     * @param node
     * @return
     */
    private JSONObject formatNode(JSONObject node) {
        JSONObject newNode = new JSONObject();
        newNode.put("node_code",node.getString("nodeCode"));
        newNode.put("node_name",node.getString("nodeName"));
        newNode.put("node_type",node.getString("nodeType"));
        newNode.put("app_code",node.getString("appCode"));
        newNode.put("tasks",node.getJSONArray("tasks"));
        newNode.put("link_str",node.getString("nodeLink"));
        return newNode;
    }


}
